package nl.weeaboo.sh.editor;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import nl.weeaboo.game.Log;
import nl.weeaboo.sh.Launcher;
import nl.weeaboo.sh.editor.area.ChangeListener;
import nl.weeaboo.sh.io.CharaImageLoader;
import nl.weeaboo.sh.model.CharaImageModel;

import org.xml.sax.SAXException;

import timon.common.components.GuiUtil;
import timon.common.components.IconListCellRenderer;
import timon.common.components.Skin;
import timon.common.components.TFileChooser;
import timon.common.io.FileUtil;
import timon.common.xml.XmlElement;

@SuppressWarnings("serial")
public class HitBoxEditor2 extends JFrame {

	private File file;
	private BufferedImage image;
	private JList imageBrowser;
	private HitBoxPanel hitBoxPanel;
	private HitBoxPropertyEditor hitBoxEditor;
	private HitBoxModeSelector modePanel;
	
	private List<CharaImageModel> charaImages;
	private String imagePath;
	private Rectangle levelRect;

	private HitBoxModeSelector.Mode mode = HitBoxModeSelector.Mode.ANCHOR;
	private CharaImageModel selected;

	public HitBoxEditor2() throws IOException {
		charaImages = new LinkedList<CharaImageModel>();
		
		imageBrowser = new JList();
		imageBrowser.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		imageBrowser.setCellRenderer(new IconListCellRenderer() {
			public Image getImageFor(Object object) {
				return null;
			}
			public String getLabelFor(Object object) {
				if (object instanceof CharaImageModel) {
					CharaImageModel image = (CharaImageModel)object;
					return image.id;
				}
				return null;
			}
		});
		imageBrowser.addListSelectionListener(new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent e) {
				CharaImageModel image = (CharaImageModel)imageBrowser.getSelectedValue();
				setSelectedCharaImage(image);
			}
		});
		
		JButton addButton = new JButton("Add");
		addButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				CharaImageModel image = new CharaImageModel();
				if (selected != null) image = selected.clone();
				
				charaImages.add(image);
				onImagesChanged();
			}
		});
		
		final JButton removeButton = new JButton("Remove");
		removeButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				charaImages.remove(selected);
				onImagesChanged();
			}
		});
		
		JPanel buttonPanel = new JPanel(new GridLayout(1, 2, 5, 5));
		buttonPanel.add(addButton);
		buttonPanel.add(removeButton);
		
		JPanel browserPanel = new JPanel(new BorderLayout(5, 5));
		browserPanel.add(new JScrollPane(imageBrowser), BorderLayout.CENTER);
		browserPanel.add(buttonPanel, BorderLayout.SOUTH);
		
		hitBoxPanel = new HitBoxPanel(levelRect);
		hitBoxPanel.addChangeListener(new ChangeListener() {
			public void onChanged(Object object) {
				CharaImageModel image = (CharaImageModel)object;
				hitBoxEditor.setSelectedImage(image);
			}
		});
		
		modePanel = new HitBoxModeSelector();
		modePanel.addChangeListener(new ChangeListener() {
			public void onChanged(Object object) {
				if (object instanceof HitBoxModeSelector.Mode) {
					mode = (HitBoxModeSelector.Mode)object;
					hitBoxPanel.setMode(mode, modePanel.getRectIndex());
				}
			}
		});

		hitBoxEditor = new HitBoxPropertyEditor(charaImages, browserPanel, modePanel);
		hitBoxEditor.addChangeListener(new ChangeListener() {
			public void onChanged(Object object) {
				//CharaImageModel image = (CharaImageModel)object;
				hitBoxPanel.redraw();
				imageBrowser.repaint();
			}
		});
		
		setLayout(new BorderLayout(5, 5));
		add(hitBoxPanel, BorderLayout.CENTER);
		add(hitBoxEditor, BorderLayout.EAST);
		
		createMenuBar();
		
		pack();
		setTitle("Scarlet Heart Hitbox Editor");
		setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		setLocationRelativeTo(null);
		setVisible(true);
	}
	
	//Functions
	public static void main(String args[]) throws IOException {
		try {
			GuiUtil.setSkin(Skin.NATIVE);
		} catch (Exception e) {
			Log.warning(e);
		}
		
		Launcher.generateResourceZip();

		HitBoxEditor2 e = new HitBoxEditor2();
		e.open("res/chara_images/sakuya.xml");		
	}
	
	public void dispose() {		
		System.out.println("Exiting...");		
		super.dispose();
	}

	protected void createMenuBar() {
		JMenuBar menuBar = new JMenuBar();
		
		JMenuItem openItem = new JMenuItem("Open");
		openItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK));
		openItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				open();
			}
		});
		
		JMenuItem saveItem = new JMenuItem("Save");
		saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK));
		saveItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				save();
			}
		});
		
		JMenu fileMenu = new JMenu("File");
		fileMenu.add(openItem);
		fileMenu.add(saveItem);
		menuBar.add(fileMenu);
		
		setJMenuBar(menuBar);
	}
	
	public void open() {
		TFileChooser filec = new TFileChooser();
		filec.setDialogType(TFileChooser.DialogType.AWT);
		filec.setMode(TFileChooser.Mode.OPEN);
		filec.setPath(file != null ? file.getAbsolutePath() : ".");
		
		if (filec.showDialog(this) == TFileChooser.OK_OPTION
				&& filec.getSelectedFile() != null)
		{
			String s = filec.getSelectedFile().getAbsolutePath();
			try {
				if (s.endsWith(".xml")) {
					open(s);
				} else {
					openImage(s);
				}
			} catch (IOException ioe) {
				Log.showError(ioe);
			}
		}
	}

	public void openImage(String path) throws IOException {
		image = ImageIO.read(new File(path));
		hitBoxPanel.setImage(image);
		file = new File(path);

		path = path.replace('\\', '/');
		if (path.lastIndexOf("res/img/") >= 0) {
			path = path.substring(path.lastIndexOf("res/img/") + 8);
		}
		
		charaImages.clear();
		imagePath = path;
		levelRect = new Rectangle(-16, -63, 32, 64);
		onImagesChanged();
		setSelectedCharaImage(null);		
	}
	public void open(String path) throws IOException {
		CharaImageLoader loader = new CharaImageLoader();
		try {
			charaImages = new LinkedList<CharaImageModel>(loader.load(path));
			imagePath = loader.getImagePath();
			levelRect = loader.getLevelRect();
		} catch (SAXException e) {
			throw new IOException(e);
		}
		
		image = ImageIO.read(new File("res/img/" + imagePath));
		hitBoxPanel.setImage(image);
		file = new File(path);
		onImagesChanged();
		
		if (charaImages.size() > 0) {
			setSelectedCharaImage(charaImages.get(0));
		} else {
			setSelectedCharaImage(null);
		}
	}
	
	public void save() {
		TFileChooser filec = new TFileChooser();
		filec.setDialogType(TFileChooser.DialogType.AWT);
		filec.setMode(TFileChooser.Mode.SAVE);
		filec.setPath(file != null ? file.getAbsolutePath() : ".");
		
		if (filec.showDialog(this) == TFileChooser.OK_OPTION
				&& filec.getSelectedFile() != null)
		{
			file = filec.getSelectedFile();

			try {
				XmlElement e = CharaImageLoader.save(imagePath, levelRect, charaImages);
				FileUtil.write(file.getAbsolutePath(), e.toXmlString());
			} catch (IOException e) {
				Log.showError(e);
			}
		}
	}
	
	public void setSelectedCharaImage(CharaImageModel image) {
		if (selected != image) {
			selected = image;
			
			hitBoxPanel.setCharaImage(levelRect, image);
			hitBoxEditor.setSelectedImage(image);
		}
	}
	
	public void onImagesChanged() {
		DefaultListModel model = new DefaultListModel();
		for (CharaImageModel image : charaImages) {
			model.addElement(image);
		}
		imageBrowser.setModel(model);
	}
	
	//Getters
	
	//Setters
	
}
